package cn.bonoon.kernel.support.services;

import org.springframework.transaction.annotation.Transactional;

import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.security.EditableException;
import cn.bonoon.kernel.support.IOperator;
import cn.bonoon.kernel.support.entities.EntityStatus;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.services.handler.DeleteDeletableHander;
import cn.bonoon.kernel.support.services.handler.DeleteHandler;
import cn.bonoon.kernel.support.services.handler.DeleteRecyclableHandler;
import cn.bonoon.kernel.support.services.handler.DeleteStandardHandler;
import cn.bonoon.kernel.support.services.handler.MultiOperateHandlerExecuter;
import cn.bonoon.kernel.support.services.handler.OperateDeleteHandler;
import cn.bonoon.kernel.support.services.handler.OperateHandler;
import cn.bonoon.kernel.support.services.handler.OperateMoveDownHandler;
import cn.bonoon.kernel.support.services.handler.OperateMoveUpHandler;
import cn.bonoon.kernel.support.services.handler.OperateStatusHandler;

/**
 * <pre>
 * 该父类是从{@link AbstractService}类抽取出来的；
 * 
 * 主要定义了对数据库实体的操作处理接口{@link OperateHandler}
 * 
 * 这些操作处理主要的方式是通过：操作符+实体ID的形式交给对应的{@link OperateHandler}处理；
 * 目前主要定义的有：
 * 1.删除。普通删、标志位删除、回收站
 * 2.禁止
 * 3.恢复
 * 4.移动(上、下、左、右)
 * 等
 * </pre>
 * @author jackson
 *
 * @param <E>
 */
public abstract class AbstractOperateService<E extends Persistable> extends AbstractSearchService<E> implements SearchService<E>, OperateService {

	protected final OperateHandler handlers[] = {
			OperateHandler.NULL,//delete
			OperateHandler.NULL,
			OperateHandler.NULL,
			OperateHandler.NULL,
			OperateHandler.NULL,
			OperateHandler.NULL,
			OperateHandler.NULL,
			OperateHandler.NULL,
			OperateHandler.NULL
	};
	
	protected DeleteHandler deleteHandler;
	
	@Override
	protected void initDeletable(EntityDescriptor entityDescriptor, Class<E> entityClass) {
		super.initDeletable(entityDescriptor, entityClass);
		if(entityDescriptor.is(EntityDescriptor.RECYCLABE)){
			deleteHandler = new DeleteRecyclableHandler();
		}else{
			deleteHandler = new DeleteDeletableHander();
		}
	}
	
	@Override
	protected void initUndeletable(EntityDescriptor entityDescriptor, Class<E> entityClass) {
		super.initUndeletable(entityDescriptor, entityClass);
		deleteHandler = new DeleteStandardHandler();
	}
	
	@Override
	protected void internalInit(EntityDescriptor entityDescriptor, Class<E> entityClass) {
		super.internalInit(entityDescriptor, entityClass);
		if(entityDescriptor.is(EntityDescriptor.STATUS)){
			handlers[OPERAND_FORBID] = new OperateStatusHandler(EntityStatus.FORBID);
			handlers[OPERAND_RESUME] = new OperateStatusHandler(EntityStatus.NORMAL);
		}
		
		handlers[OPERAND_DELETE] = new OperateDeleteHandler(deleteHandler);
	}
	
	@Override
	protected final void initMovable(EntityDescriptor entityDescriptor, Class<E> entityClass) {
		super.initMovable(entityDescriptor, entityClass);
		initMovableHandler(entityDescriptor, entityClass);
	}
	
	/** 需要先判断当前的系统是否设置了数据修改操作的限制 */
	protected void editable(IOperator operator) throws EditableException{
		operator.checkEditable();
	}
	
	protected void initMovableHandler(EntityDescriptor entityDescriptor, Class<E> entityClass){
		//上移、下移
		String name = entityDescriptor.getName();
		handlers[OPERAND_MOVE_UP] = new OperateMoveUpHandler(name);
		handlers[OPERAND_MOVE_DOWN] = new OperateMoveDownHandler(name);
	}

	@Override
	@Transactional
	public final Object operate(int operand, OperateEvent event, Long id) {
		
		editable(event);
		
		E entity = __get(event.decryptId(id));
		scopeFilter.check(event, entity);
		return _operate(operand, event, entity);
	}
	
	protected Object _operate(int operand, OperateEvent event, E entity){
		return handlers[operand].handler(entityManager, event, entity);
	}
	
	@Override
	@Transactional
	public final Object operate(int operand, OperateEvent event, Long... ids) {
		
		editable(event);
		
		MultiOperateHandlerExecuter executer = handlers[operand].handler(entityManager, event);
		for(int i = 0; i < ids.length; i ++){
			E entity = __get(event.decryptId(ids[i]));
			scopeFilter.check(event, entity);
			executer.addParameter(entity);
		}
		executer.execute();
		return null;
	}
}
